#pragma once
#include <brpc/server.h>
#include <butil/logging.h>
#include <memory>

#include "es_factory.hpp"      // es数据管理客户端封装
#include "es_user.hpp"
#include "redis.hpp"      // redis数据管理客户端封装
#include "redis_code.hpp"
#include "redis_session.hpp"
#include "redis_status.hpp"
#include "dms.hpp"

#include "mysql_user.hpp"      // mysql数据管理客户端封装
#include "etcd.hpp"     // 服务注册模块封装
#include "logger.hpp"   // 日志模块封装
#include "utils.hpp"    // 基础工具接口
#include "channel.hpp"  // 信道管理模块封装

#include "user.hxx"
#include "user-odb.hxx"

#include "user.pb.h"  // protobuf框架代码
#include "base.pb.h"  // protobuf框架代码
#include "file.pb.h"  // protobuf框架代码

class UserServiceImpl : public lch_im::UserService
{
    public:
        UserServiceImpl(const std::shared_ptr<elasticlient::Client>& es_client,
        const std::shared_ptr<odb::core::database>& mysql_client,
        const std::shared_ptr<sw::redis::Redis>& redis_client,
        const ServiceManager::ptr manager_channel,
        const std::string& file_service_name,const DMSClient::ptr& dms_client) :
        _es_user(std::make_shared<ESUser>(es_client))
        ,_mysql_user(std::make_shared<UserTable>(mysql_client)) 
        ,_redis_session(std::make_shared<Session>(redis_client))
        ,_redis_status(std::make_shared<Status>(redis_client))
        ,_redis_codes(std::make_shared<Code>(redis_client))
        ,_manager_channels(manager_channel)
        ,_file_service_name(file_service_name)
        ,_dms_client(dms_client) {
            _es_user->createIndex(); 
        }

        ~UserServiceImpl() {}

        //检查昵称的合法
        bool check_nickname(const std::string& nickname) {
            return nickname.size() < 22;
        }
        
        //检查密码的合法
        bool check_password(const std::string& password) {
            if(password.size() < 6 || password.size() > 15) {
                LOG_ERROR("密码长度不合法: {}:{}",password,password.size());
                return false;
            }

            for (int i = 0; i < password.size(); i++) {
                if (!((password[i] > 'a' && password[i] < 'z') ||
                    (password[i] > 'A' && password[i] < 'Z') ||
                    (password[i] > '0' && password[i] < '9') ||
                    password[i] == '_' || password[i] == '-') || password[i] == '!') {
                    LOG_ERROR("密码字符不合法：{}", password);
                    return false;
                }
            }
            return true;
        }
        
        bool check_phone(const std::string &phone)
        {
            if (phone.size() != 11)
                return false;
            if (phone[0] != '1')
                return false;
            if (phone[1] < '3' || phone[1] > '9')
                return false;
            for (int i = 2; i < 11; i++)
            {
                if (phone[i] < '0' || phone[i] > '9')
                    return false;
            }
            return true;
        }

        void UserRegister(google::protobuf::RpcController *controller,
                          const lch_im::UserRegisterReq *request,
                          lch_im::UserRegisterRsp *response,
                          ::google::protobuf::Closure *done)
        {
            LOG_ERROR("用户注册请求");
            brpc::ClosureGuard rpc_guard(done);
            //定义错误处理函数，不合法出错就调用
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            //1. 从请求中提取昵称和密码
            std::string nickname = request->nickname();
            std::string password = request->password();
            //2. 检查昵称是否合法
            bool ret = check_nickname(nickname);
            if(!ret) {
                LOG_ERROR("{} 用户长度不合法",request->request_id());
                return err_response(request->request_id(),"用户长度不合法");
            }
            //3. 检查密码是否合法
            ret = check_password(password);
            if(!ret) {
                LOG_ERROR("{} 密码格式不合法",request->request_id());
                return err_response(request->request_id(),"用户密码不合法");
            }
            //4. 检查昵称是否在数据中存在
            //搜索昵称，看是否存在
            auto user = _mysql_user->select_by_nickname(nickname);
            if(user) {
                LOG_ERROR("{} 用户名被占用 {}",request->request_id(),nickname);
                return err_response(request->request_id(),"用户名被占用");
            }
            //5. 如果不存在，向数据库新增数据
            std::string uid = uuid();
            user = std::make_shared<User>(uid,nickname,password);
            ret = _mysql_user->insert(user);
            if(ret == false) {
                LOG_ERROR("{} mysql数据库插入失败",request->request_id());
                return err_response(request->request_id(),"插入mysql数据库失败");
            }
            //6. 向ES添加用户信息
            ret = _es_user->appendData(uid,"",nickname,"","");
            if(ret == false) {
                LOG_ERROR("{} es数据库插入失败",request->request_id());
                return err_response(request->request_id(),"插入es数据库失败");
            }
            //7. 组织响应
            response->set_success(true);
            response->set_request_id(request->request_id());
            LOG_ERROR("用户注册请求完成");
        }
        

        void UserLogin(google::protobuf::RpcController *controller,
                          const lch_im::UserLoginReq *request,
                          lch_im::UserLoginRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            //1. 从请求中取出昵称和密码 
            std::string nickname = request->nickname();
            std::string password = request->password();
            //2. 通过昵称获取用户信息，进行密码是否一致的判断 
            auto user = _mysql_user->select_by_nickname(nickname);
            if(!user || password != user->password()) {
                LOG_ERROR("{} - 用户名或密码错误 - {}-{}！", request->request_id(), nickname, password);
                return err_response(request->request_id(), "用户名或密码错误!");
            }
            //3. 根据 redis 中的登录标记信息是否存在判断用户是否已经登录
            bool ret =  _redis_status->exists(request->request_id());
            if(ret) {
                LOG_ERROR("{} 用户已在其他地方登陆",request->request_id());
                return err_response(request->request_id(),"用户已在其他地方登录");
            }
            //4. 构造会话 ID，生成会话键值对，向 redis 中添加会话信息以及登录标记信息
            std::string ssid = uuid(); 
            _redis_session->append_session_id(ssid,user->user_id());
            //5. 组织响应，返回生成的会话 ID 
            response->set_success(true);
            response->set_request_id(request->request_id());
            response->set_login_session_id(ssid);
        }
 
        void GetPhoneVerifyCode(google::protobuf::RpcController *controller,
                          const lch_im::PhoneVerifyCodeReq *request,
                          lch_im::PhoneVerifyCodeRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            //1. 从请求中取出手机号码
            std::string phone = request->phone_number();
            //2. 验证手机号码格式是否正确（必须以 1 开始，第二位 3~9 之间，后边 9 个数字字符
            bool ret = check_phone(phone);
            if(!ret) {
                LOG_ERROR("{} 手机号格式错误 {}",request->request_id(),phone);
                return err_response(request->request_id(),"手机号格式错误");
            }
            //3. 生成 4 位随机验证码 
            std::string code_id = uuid();
            std::string code = vcode();
            //4. 基于短信平台 SDK 发送验证码
            ret = _dms_client->send(request->phone_number(),code);
            if (ret == false) {
                LOG_ERROR("{} - 短信验证码发送失败 - {}！", request->request_id(), phone);
                return err_response(request->request_id(), "短信验证码发送失败!");
            }
            //5. 构造验证码 ID，添加到 redis 验证码映射键值索引中 
            _redis_codes->append_code(code_id,code);
            //6. 组织响应，返回生成的验证码 ID
            response->set_request_id(request->request_id());
            response->set_success(true);
            response->set_verify_code_id(code_id);
      }

        void PhoneRegister(google::protobuf::RpcController *controller,
                          const lch_im::PhoneRegisterReq *request,
                          lch_im::PhoneRegisterRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            //1. 从请求中取出手机号码和验证码 
            std::string phone = request->phone_number();
            std::string code_id = request->verify_code_id();
            std::string code = request->verify_code();
            //2. 检查注册手机号码是否合法
            bool ret = check_phone(phone);
            if(!ret) {
                LOG_ERROR("{} 手机号格式错误 {}",request->request_id(),phone);
                return err_response(request->request_id(),"手机号格式错误");
            } 
            //3. 从 redis 数据库中进行验证码 ID-验证码一致性匹配 
            auto vcode = _redis_codes->code(code_id);
            if(vcode != code) {
                LOG_ERROR("{} 验证码不一致 {}-{}",request->request_id(),code_id,code);
                return err_response(request->request_id(),"验证码不一致");
            }
            //4. 通过数据库查询判断手机号是否已经注册过
            auto user = _mysql_user->select_by_phone(phone);
            if(user) {
                LOG_ERROR("{} - 该手机号已注册过用户 - {}！", request->request_id(), phone);
                return err_response(request->request_id(), "该手机号已注册过用户!");
            } 
            //5. 向数据库新增用户信息
            std::string uid = uuid();
            user = std::make_shared<User>(uid, phone);
            ret = _mysql_user->insert(user);
            if (!ret)
            {
                LOG_ERROR("{} 向mysql数据库中添加用户信息失败 {}", request->request_id(), phone);
                return err_response(request->request_id(), "向数据库中添加用户信息失败");
            }
            // 6. 向 ES 服务器中新增用户信息
            ret = _es_user->appendData(uid, phone, "", "", uid);
            if (!ret)
            {
                LOG_ERROR("{} es数据库插入失败", request->request_id());
                return err_response(request->request_id(), "插入es数据库失败");
            }
            // 7. 组织响应
            response->set_success(true);
            response->set_request_id(request->request_id());
        }

        void PhoneLogin(google::protobuf::RpcController *controller,
                          const lch_im::PhoneLoginReq *request,
                          lch_im::PhoneLoginRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            //从请求中取出手机号和验证码
            std::string phone = request->phone_number();
            std::string code_id = request->verify_code_id();
            std::string code = request->verify_code();

            //检查手机号是否合法
            bool ret = check_phone(phone);
            if(ret == false) {
                LOG_ERROR("{} - 手机号码格式错误 - {}！", request->request_id(), phone);
                return err_response(request->request_id(), "手机号码格式错误!");
            }
            //根据手机号进行用户信息查询，判断用户是否存在
            auto user = _mysql_user->select_by_phone(phone);
            if(!user) 
            {
                LOG_ERROR(" {} 手机号没有注册用户 {}",request->request_id(),phone);
                return err_response(request->request_id(),"手机号没有被注册");
            }

            //根redis中的验证码判断
            auto vcode = _redis_codes->code(code_id);
            if(vcode != code) 
            {
                LOG_ERROR("{} - 验证码错误 - {}-{}！", request->request_id(), code_id, code);
                return err_response(request->request_id(), "验证码错误!");
            }

            _redis_codes->remove_cid(code_id);
            //判断用户是否已经的登录了
            ret = _redis_status->exists(user->user_id());
            if(ret == true) 
            {
                LOG_ERROR("{} 用户已经在其他地方登录 {}",request->request_id(),phone);
                return err_response(request->request_id(),"用户已经在其他地方登录了");
            }
            //构造会话ID，向redis中添加会话信息等
            std::string ssid = uuid();
            _redis_session->append_session_id(ssid,user->user_id());
            //如果没有登陆，那么就需要向redis中添加登录状态
            _redis_status->append_status_uid(user->user_id());
            
            //组织响应
            response->set_request_id(request->request_id());
            response->set_login_session_id(ssid);
            response->set_success(true);
        }

        void GetUserInfo(google::protobuf::RpcController *controller,
                          const lch_im::GetUserInfoReq *request,
                          lch_im::GetUserInfoRsp *response,
                          ::google::protobuf::Closure *done)
        {
            LOG_DEBUG("收到获取单个用户信息请求！");
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            // 1. 从请求中取出用户 ID
            std::string uid = request->user_id();
            // 2. 通过用户 ID，从数据库中查询用户信息
            auto user = _mysql_user->select_by_id(uid);
            if(!user) {
                LOG_ERROR("{} 没有找到用户 {}",request->request_id(),uid);
                return err_response(request->request_id(),"没有找到用户");
            }
            // 3. 根据用户信息中的头像 ID，从文件服务器获取头像文件数据，组织完整用户信息
            //response->mutable_user_info() 已经将user_info存放到response中了， 不再需要手动添加到reesponose中
            lch_im::UserInfo* user_info = response->mutable_user_info();
            user_info->set_user_id(user->user_id());
            user_info->set_nickname(user->nickname());
            user_info->set_description(user->description());
            user_info->set_phone(user->phone());

            if(!(user->avatar_id()).empty()) {
                //通过通道获取到channel，然后发起rpc调用开始调用文件服务
                auto channel = _manager_channels->choose(_file_service_name);
                if(!channel) {
                    LOG_ERROR("{} 没有找到文件管理通道 {}",request->request_id(),uid);
                    return err_response(request->request_id(),"没有找到文件管理通道");
                }

                //进行rpc调用
                lch_im::FileService_Stub stub(channel.get());
                lch_im::GetSingleFileReq req;
                lch_im::GetSingleFileRsp rsp;
                req.set_request_id(request->request_id());
                req.set_file_id(user->avatar_id());
                LOG_DEBUG("{}",user->avatar_id());
                brpc::Controller cntl;
                stub.GetSingleFile(&cntl,&req,&rsp,nullptr);
                if (cntl.Failed() == true || rsp.success() == false) {
                    LOG_ERROR("{} - 文件子服务调用失败：{}！", request->request_id(), cntl.ErrorText());
                    return err_response(request->request_id(), "文件子服务调用失败!");
                }
                user_info->set_avatar(rsp.file_data().file_content());
            }
            // 4. 组织响应，返回用户信息
            response->set_request_id(request->request_id());
            response->set_success(true);
            LOG_DEBUG("单个用户请求完成");
          }

        void GetMultiUserInfo(google::protobuf::RpcController *controller,
                          const lch_im::GetMultiUserInfoReq *request,
                          lch_im::GetMultiUserInfoRsp *response,
                          ::google::protobuf::Closure *done)
        {
            LOG_DEBUG("收到获取批量用户信息");
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            std::vector<std::string> uid_lists;
            for (int i = 0; i < request->users_id_size(); i++) {
                uid_lists.push_back(request->users_id(i));
            }
            //从数据库中获取批量的数据
            auto users = _mysql_user->select_multi_users(uid_lists);
            if (users.size() != request->users_id_size()) {
                LOG_ERROR("{} 从mysql数据库查找的数据数量不一致 {}:{}",request->request_id(),request->users_id_size(),users.size());
                return err_response(request->request_id(),"从mysql数据库中查找的数据数量不一致");
            }

            //批量从文件子服务中获取文件
            auto channel = _manager_channels->choose(_file_service_name);
            if (!channel)
            {
                LOG_ERROR("{} 没有找到文件管理通道 {}", request->request_id(), _file_service_name);
                return err_response(request->request_id(), "没有找到文件管理通道");
            }

            lch_im::FileService_Stub stub(channel.get());
            lch_im::GetMultiFileReq req;
            lch_im::GetMultiFileRsp rsp;
            req.set_request_id(request->request_id());
            for (auto &user : users)
            {
                if (user.avatar_id().empty())
                {
                    continue; // 如果 avatar_id 为 null 或为空，则跳过
                }
                req.add_file_id_list(user.avatar_id());
            }

            brpc::Controller cntl;
            stub.GetMultiFile(&cntl,&req,&rsp,nullptr);
            if (cntl.Failed() == true || rsp.success() == false) {
                LOG_ERROR("{} - 文件子服务调用失败：{} - {}！", request->request_id(), 
                    _file_service_name, cntl.ErrorText());
                return err_response(request->request_id(), "文件子服务调用失败!");
            }
            //组织响应
            for(auto e : users) {
                auto user_map = response->mutable_users_info();//本次请求要响应的用户信息map
                auto file_map = rsp.mutable_file_data(); //这是批量文件请求响应中的map 
                lch_im::UserInfo user_info;
                user_info.set_user_id(e.user_id());
                user_info.set_nickname(e.nickname());
                user_info.set_description(e.description());
                user_info.set_phone(e.phone());
                user_info.set_avatar((*file_map)[e.avatar_id()].file_content());
                (*user_map)[user_info.user_id()] = user_info;
            }
            response->set_request_id(request->request_id());
            response->set_success(true);
            LOG_DEBUG("批量获取用户信息完成");
        }

        void SetUserAvatar(google::protobuf::RpcController *controller,
                          const lch_im::SetUserAvatarReq *request,
                          lch_im::SetUserAvatarRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            // 1. 从请求中取出用户 ID 与头像数据
            std::string uid = request->user_id();
            // 2. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto user = _mysql_user->select_by_id(uid);
            if(!user) {
                LOG_ERROR("{} 未找到用户信息 {}",request->request_id(),uid);
                return err_response(request->request_id(),"未找到用户信息");
            } 
            // 3. 上传头像文件到文件子服务，
            auto channel = _manager_channels->choose(_file_service_name);
            if(!channel) {
                LOG_ERROR("{} 未找到文件子服务的节点 {}",request->request_id(),_file_service_name);
                return err_response(request->request_id(),"未找到文件子服务节点");
            }
            lch_im::FileService_Stub stub(channel.get());
            lch_im::PutSingleFileReq req;
            lch_im::PutSingleFileRsp rsp;
            req.set_request_id(request->request_id());
            req.mutable_file_data()->set_file_name("");
            req.mutable_file_data()->set_file_size(request->avatar().size());
            req.mutable_file_data()->set_file_content(request->avatar());
            brpc::Controller cntl;
            stub.PutSingleFile(&cntl,&req,&rsp,nullptr);
            if (cntl.Failed() == true || rsp.success() == false) {
                LOG_ERROR("{} - 文件子服务调用失败：{}！", request->request_id(), cntl.ErrorText());
                return err_response(request->request_id(), "文件子服务调用失败!");
            }
            std::string avatar_id = rsp.file_info().file_id();
            // 4. 将返回的头像文件 ID 更新到数据库中
            user->set_avatar_id(avatar_id);
            bool ret = _mysql_user->update(user);
            if(!ret) {
                LOG_ERROR("{} 更新到数据库用户头像ID失败： {}",request->request_id(),avatar_id);
                return err_response(request->request_id(),"更新到数据库头像ID失败");
            }
            // 5. 更新 ES 服务器中用户信息
            ret = _es_user->appendData(user->user_id(), user->phone(),
            user->nickname(), user->description(), user->avatar_id());
            if (ret == false) {
                LOG_ERROR("{} - 更新搜索引擎用户头像ID失败 ：{}！", request->request_id(), avatar_id);
                return err_response(request->request_id(), "更新搜索引擎用户头像ID失败!");
            }
            // 6. 组织响应，返回更新成功与否
            response->set_success(true);
            response->set_request_id(request->request_id());
        }

        void SetUserNickname(google::protobuf::RpcController *controller,
                          const lch_im::SetUserNicknameReq *request,
                          lch_im::SetUserNicknameRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };

            // 1. 从请求中取出用户 ID 与新的昵称
            std:;string uid = request->user_id();
            std::string new_nickname = request->nickname();
            // 2. 判断昵称格式是否正确 
            bool ret = check_nickname(new_nickname);
            if(!ret) {
                LOG_ERROR("{} 用户长度不合法 {}",request->request_id(),new_nickname);
                return err_response(request->request_id(),"用户长度不合法");
            }
            // 3. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto user = _mysql_user->select_by_id(uid);
            if(!user) {
                LOG_ERROR("{} 没有找到用户信息 {}",request->request_id(),uid);
                return err_response(request->request_id(),"没有找到用户信息");
            } 
            // 4. 将新的昵称更新到数据库中 
            user->set_nickname(new_nickname);
            ret = _mysql_user->update(user);
            if (ret == false) {
                LOG_ERROR("{} - 更新数据库用户昵称失败 ：{}！", request->request_id(), new_nickname);
                return err_response(request->request_id(), "更新数据库用户昵称失败!");
            }
            // 5. 更新 ES 服务器中用户信息
            ret = _es_user->appendData(user->user_id(), user->phone(),
            user->nickname(), user->description(), user->avatar_id());
            if (ret == false) {
                LOG_ERROR("{} - 更新搜索引擎用户昵称失败 ：{}！", request->request_id(), user->user_id());
                return err_response(request->request_id(), "更新搜索引擎用户昵称失败!");
            }
            // 6. 组织响应，返回更新成功与否
            response->set_success(true);
            response->set_request_id(request->request_id());
        }

        void SetUserDescription(google::protobuf::RpcController *controller,
                          const lch_im::SetUserDescriptionReq *request,
                          lch_im::SetUserDescriptionRsp *response,
                          ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };

            // 1. 从请求中取出用户 ID 与新的签名
            std::string uid = request->user_id();
            std::string description = request->description();
            // 2. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto user = _mysql_user->select_by_id(uid);
            if (!user)
            {
                LOG_ERROR("{} 没有找到用户信息 {}", request->request_id(), uid);
                return err_response(request->request_id(), "没有找到用户信息");
            }
            // 3. 将新的签名更新到数据库中
            user->set_nickname(description);
            bool ret = _mysql_user->update(user);
            if (ret == false)
            {
                LOG_ERROR("{} - 更新数据库用户签名失败 ：{}！", request->request_id(), uid);
                return err_response(request->request_id(), "更新数据库用户签名失败!");
            }
            // 4. 更新 ES 服务器中用户信息
            ret = _es_user->appendData(user->user_id(), user->phone(),
                                       user->nickname(), user->description(), user->avatar_id());
            if (ret == false)
            {
                LOG_ERROR("{} - 更新搜索引擎用户签名失败 ：{}！", request->request_id(), user->user_id());
                return err_response(request->request_id(), "更新搜索引擎用户签名失败!");
            }
            // 5. 组织响应，返回更新成功与否
            response->set_success(true);
            response->set_request_id(request->request_id());
        }

        void SetUserPhoneNumber(google::protobuf::RpcController *controller,
                                const lch_im::SetUserPhoneNumberReq *request,
                                lch_im::SetUserPhoneNumberRsp *response,
                                ::google::protobuf::Closure *done)
        {
            brpc::ClosureGuard rpc_guard(done);
            auto err_response = [this,response](const std::string& rid,const std::string& errmsg)->void
            {
                response->set_request_id(rid);
                response->set_success(false);
                response->set_errmsg(errmsg);
            };
            // 1. 从请求中取出手机号码和验证码 ID，以及验证码。
            std::string uid = request->user_id();
            std::string new_phone = request->phone_number();
            std::string verify_code_id = request->phone_verify_code_id();
            std::string verify_code = request->phone_verify_code(); 
            // 2. 检查注册手机号码是否合法
            bool ret = check_phone(new_phone);
            if(!ret) {
                LOG_ERROR("{} 手机号不合法 {}",request->request_id(),new_phone);
                return err_response(request->request_id(),"手机号不合法");
            }
            // 3. 对验证码进行验证
            auto vcode = _redis_codes->code(verify_code_id);
            if (vcode != verify_code) {
                LOG_ERROR("{} - 验证码错误 - {}-{}！", request->request_id(), verify_code_id, verify_code);
                return err_response(request->request_id(), "验证码错误!");
            }
            // 4. 从数据库通过用户 ID 进行用户信息查询，判断用户是否存在
            auto user = _mysql_user->select_by_id(uid);
            if (!user) {
                LOG_ERROR("{} - 未找到用户信息 - {}！", request->request_id(), uid);
                return err_response(request->request_id(), "未找到用户信息!");
            }
            // 5. 将新的昵称更新到数据库中
            user->set_phone(new_phone);
            ret = _mysql_user->update(user);
            if (ret == false) {
                LOG_ERROR("{} - 更新数据库用户手机号失败 ：{}！", request->request_id(), new_phone);
                return err_response(request->request_id(), "更新数据库用户手机号失败!");
            }
            // 6. 更新 ES 服务器中用户信息
            ret = _es_user->appendData(user->user_id(), user->phone(),
                user->nickname(), user->description(),user->avatar_id());
            if (ret == false) {
                LOG_ERROR("{} - 更新搜索引擎用户手机号失败 ：{}！", request->request_id(), new_phone);
                return err_response(request->request_id(), "更新搜索引擎用户手机号失败!");
            }
            // 7. 组织响应，返回更新成功与否
            response->set_request_id(request->request_id());
            response->set_success(true);
        }

    private:
        ESUser::ptr _es_user;
        UserTable::ptr _mysql_user;
        Session::ptr _redis_session;
        Status::ptr _redis_status;
        Code::ptr _redis_codes;
        // 这边是rpc调用客户端相关对象
        std::string _file_service_name;
        ServiceManager::ptr _manager_channels;
        DMSClient::ptr _dms_client;
};



class UserServer
{
    public:       
    using ptr = std::shared_ptr<UserServer>;

    UserServer(const Discovery::ptr& service_discoverer,const std::shared_ptr<elasticlient::Client> es_client,
    const std::shared_ptr<odb::core::database> mysql_client,
    const std::shared_ptr<sw::redis::Redis> redis_client, 
    const Registery::ptr& reg_client,const std::shared_ptr<brpc::Server> rpc_server) :_service_discoverer(service_discoverer),
    _es_client(es_client),
    _mysql_client(mysql_client),
    _redis_client(redis_client),
    _reg_client(reg_client),
    _rpc_server(rpc_server) {}

    ~UserServer() {}

    void start()
    {
        _rpc_server->RunUntilAskedToQuit();
    }   

    private:
        Discovery::ptr _service_discoverer;
        std::shared_ptr<elasticlient::Client> _es_client;
        std::shared_ptr<odb::core::database> _mysql_client;
        std::shared_ptr<sw::redis::Redis> _redis_client;
        Registery::ptr _reg_client;
        std::shared_ptr<brpc::Server> _rpc_server;
};

class UserServerBuild
{
    public:
    void create_dms_object(const std::string& access_key_id,const std::string& access_key_secret) {
        _dms_client = std::make_shared<DMSClient>(access_key_id,access_key_secret);
    }

    //创建es对象
    void create_es_object(const std::vector<std::string> host_list) 
    {
        _es_client = ESClientFactory::create(host_list);
    }

    //创建mysql对象
    void create_mysql_object(
            const std::string& user,
            const std::string& pswd,
            const std::string& db,
            const std::string& host,
            const std::string& cset,
            int port,
            int connect_pool_count)
        {
            _mysql_client = ODBFactory::create(user,pswd,db,host,cset,port,connect_pool_count);
        }

    void create_redis_object(const std::string& host,int port,int db,bool keep_alive)
    {
        _redis_client = RedisClientFactory::create(host,port,db,keep_alive);
    }

    void create_discovery_object(const std::string& reg_host,
    const std::string& base_service_name,
    const std::string& file_service_name)
    {
        _file_service_name = file_service_name;
        _manager_channels = std::make_shared<ServiceManager>();
        //设置关心的对象
        _manager_channels->declared(_file_service_name);
        auto pub_cb = std::bind(&ServiceManager::onServiceOnline,_manager_channels.get(),std::placeholders::_1,std::placeholders::_2);
        auto del_cb = std::bind(&ServiceManager::onServiceOffline,_manager_channels.get(),std::placeholders::_1,std::placeholders::_2);
        _service_discoverer = std::make_shared<Discovery>(reg_host,base_service_name,pub_cb,del_cb);
    }

    void create_registry_object(const std::string &reg_host, const std::string &service_name, const std::string &access_host)
    {
        _registery_client = std::make_shared<Registery>(reg_host);
        _registery_client->registry(service_name, access_host);
    }

    void create_rpc_object(uint16_t port, int32_t timeout, uint8_t num_threads,const std::string& path = "./data/")
    { 
        if(!_dms_client) {
            LOG_ERROR("还未初始化dms客户端");
            abort();
        }

        if(!_es_client) {
            LOG_ERROR("还未初始化es客户端");
            abort();
        }

        if(!_mysql_client) {
            LOG_ERROR("还未初始化mysql客户端");
            abort();
        }

        if(!_redis_client) {
            LOG_ERROR("还未初始化redis客户端");
            abort();
        }

        if (!_manager_channels) {
            LOG_ERROR("还未初始化信道管理模块！");
            abort();
        }
        _rpc_server = std::make_shared<brpc::Server>();
        UserServiceImpl *user_service = new UserServiceImpl( _es_client,
                                                            _mysql_client, _redis_client, _manager_channels, _file_service_name,_dms_client);
        int ret = _rpc_server->AddService(user_service,
                                          brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
        if (ret == -1)
        {
            LOG_ERROR("添加Rpc服务失败！");
            abort();
        }

        // 启动服务器
        brpc::ServerOptions options;
        // 连接空闲超时时间，-1表示
        options.idle_timeout_sec = -1;
        // io线程数量
        options.num_threads = 1;
        ret = _rpc_server->Start(port, &options);
        if (ret == -1)
        {
            LOG_ERROR("服务启动失败");
            abort();
        }
    }

    UserServer::ptr build()
    {
        if(!_service_discoverer) {
            LOG_ERROR("没有初始化服务发现服务");
            abort();
        }

          if (!_registery_client)
        {
            LOG_ERROR("没有初始化服务注册服务");
            abort();
        }

        if (!_rpc_server)
        {
            LOG_ERROR("没有初始化rpc服务");
            abort();
        }

        UserServer::ptr server = std::make_shared<UserServer>(_service_discoverer,_es_client,_mysql_client,_redis_client,
        _registery_client,_rpc_server);
        return server;
    }

    private:
        Registery::ptr _registery_client;

        std::shared_ptr<elasticlient::Client> _es_client;
        std::shared_ptr<odb::core::database> _mysql_client;
        std::shared_ptr<sw::redis::Redis> _redis_client;

        std::string _file_service_name;
        ServiceManager::ptr _manager_channels;
        Discovery::ptr _service_discoverer;

        std::shared_ptr<DMSClient> _dms_client;

        std::shared_ptr<brpc::Server> _rpc_server;
};
